/* Copyright (C) 2018-2025 Free Software Foundation, Inc.

This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.

This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.

You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
<http://www.gnu.org/licenses/>.  */

/* An executable stack is *not* required for these functions.  */
#ifdef __linux__
.section .note.GNU-stack,"",%progbits
.previous
#endif

#ifdef L__mulsi3
	.balign 4
	.globl	__mulsi3
	.type	__mulsi3, @function
__mulsi3:
	l.movhi		r11, 0			/* initial r */

	/* Given R = X * Y ... */
1:	l.sfeq		r4, r0			/* while (y != 0) */
	l.bf		2f
	 l.andi		r5, r4, 1		/* if (y & 1) ... */
	l.add		r12, r11, r3
	l.sfne		r5, r0
#if defined(__or1k_cmov__)
	l.cmov		r11, r12, r11		/* ... r += x. */
	l.srli		r4, r4, 1		/* y >>= 1 */
#else
	l.bnf		3f
	 l.srli		r4, r4, 1		/* y >>= 1 */
	l.ori		r11, r12, 0
3:
#endif
	l.j		1b
	 l.add		r3, r3, r3		/* x <<= 1 */

2:	l.jr		r9
	 l.nop

	.size	__mulsi3, . - __mulsi3
#endif

#if defined(L__udivsi3) || defined(L__umodsi3) \
    || defined(L__divsi3) || defined(L__modsi3)
	.global	__udivmodsi3_internal
	.hidden	__udivmodsi3_internal
	.type	__udivmodsi3_internal, @function
#endif

#ifdef L__udivsi3
	.balign	4
	.global	__udivsi3
	.type	__udivsi3, @function
__udivsi3:
__udivmodsi3_internal:
	/* Note that the other division routines assume that r13
	   is not clobbered by this routine, and use that as to
	   save a return address without creating a stack frame.  */

	l.sfeq		r4, r0		/* division by zero; return 0.  */
	l.ori		r11, r0, 0	/* initial quotient */
	l.bf		9f
	 l.ori		r12, r3, 0	/* initial remainder */

	/* Given X/Y, shift Y left until Y >= X.  */
	l.ori		r6, r0, 1	/* mask = 1 */
1:	l.sflts		r4, r0		/* y has msb set */
	l.bf		2f
	 l.sfltu	r4, r12		/* y < x */
	l.add		r4, r4, r4	/* y <<= 1 */
	l.bf		1b
	 l.add		r6, r6, r6	/* mask <<= 1 */

	/* Shift Y back to the right again, subtracting from X.  */
2:	l.add		r7, r11, r6	/* tmp1 = quot + mask */
3:	l.srli		r6, r6, 1	/* mask >>= 1 */
	l.sub		r8, r12, r4	/* tmp2 = x - y */
	l.sfleu		r4, r12		/* y <= x */
	l.srli		r4, r4, 1	/* y >>= 1 */
#if defined(__or1k_cmov__)
	l.cmov		r11, r7, r11	/* if (y <= x) quot = tmp1 */
	l.cmov		r12, r8, r12	/* if (y <= x) x = tmp2 */
#else
	l.bnf		4f
	 l.nop
	l.ori		r11, r7, 0
	l.ori		r12, r8, 0
4:
#endif
	l.sfne		r6, r0		/* loop until mask == 0 */
	l.bf		3b
	 l.add		r7, r11, r6	/* delay fill from loop start */

9:	l.jr		r9
	 l.nop

	.size	__udivsi3, . - __udivsi3
	.size	__udivmodsi3_internal, . - __udivmodsi3_internal
#endif

#ifdef L__umodsi3
	.balign	4
	.global	__umodsi3
	.type	__umodsi3, @function
	.cfi_startproc
__umodsi3:
	/* Know that __udivmodsi3_internal does not clobber r13.  */
	l.ori		r13, r9, 0
	.cfi_register	9, 13
	l.jal		__udivmodsi3_internal
	 l.nop
	l.jr		r13		/* return to saved lr */
	 l.ori		r11, r12, 0	/* move remainder to rv */

	.cfi_endproc
	.size	__umodsi3, . - __umodsi3
#endif

/* For signed division we do:

     -x / y = x / -y = -(x / y)
     -x % y = -(x % y)
      x % -y = x % y

   which has the property that (x/y)*y + (x%y) = x.  */

#ifdef L__divsi3
	.balign	4
	.global	__divsi3
	.type	__divsi3, @function
	.cfi_startproc
__divsi3:
	l.xor		r6, r3, r4	/* need result negate?  */

	l.sflts		r3, r0		/* abs(x) */
#if defined(__or1k_cmov__)
	l.sub		r5, r0, r3
	l.cmov		r3, r5, r3
#else
	l.bnf		1f
	 l.sub		r5, r0, r3
	l.ori		r3, r5, 0
1:
#endif
	l.sflts		r4, r0		/* abs(y) */
#if defined(__or1k_cmov__)
	l.sub		r5, r0, r4
	l.cmov		r4, r5, r4
#else
	l.bnf		2f
	 l.sub		r5, r0, r4
	l.ori		r4, r5, 0
2:
#endif

	/* If the result will not require sign flip, tail call.  */
	l.sflts		r6, r0
	l.bnf		__udivmodsi3_internal
	 l.ori		r13, r9, 0	/* save lr */

	/* Otherwise, know that __udivmodsi3_internal does not clobber r13.
	   Perform a normal call, then negate and return via saved lr.  */
	.cfi_register	9, 13
	l.jal		__udivmodsi3_internal
	 l.nop
	l.jr		r13
	 l.sub		r11, r0, r11

	.cfi_endproc
	.size	__divsi3, . - __divsi3
#endif

#ifdef L__modsi3
	.balign	4
	.global	__modsi3
	.type	__modsi3, @function
	.cfi_startproc
__modsi3:
	l.sflts		r4, r0		/* abs(y) */
#if defined(__or1k_cmov__)
	l.sub		r5, r0, r4
	l.cmov		r4, r5, r4
#else
	l.bnf		2f
	 l.sub		r5, r0, r4
	l.ori		r4, r5, 0
2:
#endif

	l.sflts		r3, r0		/* x negative? */
	l.bf		1f
	 l.ori		r13, r9, 0	/* save lr */

	/* Know that __udivmodsi3_internal does not clobber r13.  */
	.cfi_register	9, 13

	/* X positive; no negate of the result required.  */
	l.jal		__udivmodsi3_internal
	 l.nop
	l.jr		r13		/* return to saved lr */
	 l.ori		r11, r12, 0	/* move remainder to rv */

	/* X negative; negate both X and the result.  */
1:	l.jal		__udivmodsi3_internal
	 l.sub		r3, r0, r3
	l.jr		r13		/* return to saved lr */
	 l.sub		r11, r0, r12	/* negate remainder to rv */

	.cfi_endproc
	.size __modsi3, .- __modsi3
#endif
